/*
 * Copyright DimYLiK.
 */

package com.example.myapp.utilities;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

public class AntiBaldaLogic {

    private static final int POLE_SIZE = 5;
    private static final int POSSIBLE_HOD = 4;
    private static final String X = ".";
    private Map<String, String> fullVocabularyMap = new HashMap<String, String>();
    private Map<Integer, HashSet<String>> vocabularyMap = new HashMap<Integer, HashSet<String>>();
    private Set<String> possibleWords = new HashSet<String>();
    private String[][] pole = new String[][]
            {
                    {X, X, X, X, X},
                    {X, X, X, X, X},
                    {"?", "?", "?", "?", "?"},
                    {X, X, X, X, X},
                    {X, X, X, X, X}
            };

    private int[][] hod = new int[][]
            {  // s levogo polja po 4asovoj strelke:  [i, j-1], [i-1, j], [i, j+1], [i+1, j]
                    {0, -1, 0, 1},
                    {-1, 0, 1, 0}
            };


    public static void main(String... args) {
        try {
            AntiBaldaLogic balda = new AntiBaldaLogic();
//            balda.readVocabulary("");
            balda.updateVocabularyByLength();

            balda.calculatePossibleWords();
//            balda.findAlSequence();
            balda.optimizeSequence();
            balda.findWords();
            throw new FileNotFoundException();
        } catch (FileNotFoundException e) {
            System.out.println("Vocabulary file not found...");
        } catch (IOException e) {
            System.out.println("Vocabulary read error...");
        } catch (UnsupportedOperationException e) {
            System.out.println("Ne verno pro4itano: " + e.toString());
        } catch (StringIndexOutOfBoundsException e) {
            System.out.println("Ne praviljnie operacii s tekstom: " + e.toString());
        }
    }

    private void findWords() {
        Map<Integer, HashSet<String>> possibleWordsMap = new HashMap<Integer, HashSet<String>>();
        for (String word : possibleWords) {
            Integer len = word.length();
            HashSet<String> words;
            if (possibleWordsMap.containsKey(len)) {
                words = possibleWordsMap.get(len);
            } else {
                words = new HashSet<String>();
            }
            words.add(word);
            possibleWordsMap.put(len, words);
        }

        Set<String> result = new HashSet<String>();
        for (Integer len : possibleWordsMap.keySet()) {
            Set<String> wordSequence = possibleWordsMap.get(len);
            Set<String> vocabularyWords = vocabularyMap.get(len);
            for (String sequence : wordSequence) {
                Pattern pattern = Pattern.compile(sequence);
                for (String vocabulary : vocabularyWords) {
                    if (pattern.matcher(vocabulary).matches()) {
                        result.add(vocabulary);
                    }
                }
            }
        }

        List<String> resultList = new ArrayList<String>(result);
        Collections.sort(resultList, new Comparator<String>() {
            public int compare(String o1, String o2) {
                return Integer.valueOf(o2.length()).compareTo(o1.length());
            }
        });
        System.out.println("Realjnie slova:");
        System.out.println("+++++++ NACHALO +++++++");
        for (String word : resultList) {
            System.out.println(word);
        }
        System.out.println("+++++++ KONEC +++++++");
    }

    private void optimizeSequence() {
        possibleWords.remove(X);
        Set<String> newPossibleWords = new HashSet<String>();
        System.out.println("Realjnie maski slov:");
        System.out.println("+++++++ NACHALO +++++++");
        for (String word : possibleWords) {
            if (word.indexOf(X) > -1) {
                System.out.println(word);
                newPossibleWords.add(word);
            }
        }
        System.out.println("+++++++ KONEC +++++++");
        possibleWords.clear();
        possibleWords.addAll(newPossibleWords);
    }

    private void findAlSequence() {
        System.out.println("Vozmozhnie slova:");
        System.out.println("+++++++ NACHALO +++++++");
        for (String possibleWord : possibleWords) {
            System.out.println(possibleWord);
        }
        System.out.println("+++++++ KONEC +++++++");
    }

    private void calculatePossibleWords() {
        possibleWords.clear();
        for (int i = 0; i < POLE_SIZE; i++) {
            for (int j = 0; j < POLE_SIZE; j++) {
                mainCycle(i, j);
            }
        }
    }

    private void mainCycle(int i, int j) {
        String moves = logCurrentMove(i, j);
        String possibleWord = pole[i][j];
        fullCycle(i, j, possibleWord, moves);
    }

    private String fullCycle(int i, int j, String possibleWord, String moves) {
        for (int x = 0; x < POSSIBLE_HOD; x++) {
            int new_i = i + hod[0][x];
            int new_j = j + hod[1][x];
            if (new_i > -1 && new_i < POLE_SIZE && new_j > -1 && new_j < POLE_SIZE) {
                String currentMove = logCurrentMove(new_i, new_j);
                String letter = pole[new_i][new_j];
                if (possibleWord.indexOf(X + X) > -1) {
                    possibleWords.add(possibleWord);
                } else if (moves.indexOf(currentMove) > -1) {
                    possibleWords.add(possibleWord);
                } else if (X.equals(letter) && possibleWord.indexOf(X) > -1) {
                    possibleWords.add(possibleWord);
                } else {
                    possibleWords.add(possibleWord + letter);
                    possibleWords.add(fullCycle(new_i, new_j, possibleWord + letter, moves + currentMove));
                }
            }
        }
        return possibleWord;
    }

    private String logCurrentMove(int new_i, int new_j) {
        String currentMove = "[" + String.valueOf(new_i) + ":" + String.valueOf(new_j) + "]";
        return currentMove;
    }

    private void updateVocabularyByLength() {
        for (String word : fullVocabularyMap.keySet()) {
            int len = word.length();
            HashSet<String> words;
            if (vocabularyMap.containsKey(len)) {
                words = vocabularyMap.get(len);
            } else {
                words = new HashSet<String>();
            }
            words.add(word);
            vocabularyMap.put(len, words);
        }

//        System.out.println("Slovarj razlozhen po dline slov (" + vocabularyMap.size() + ")");
//        for (int i = 0; i < vocabularyMap.size(); i++) {
//            System.out.println((i + 1) + " bukv = " + vocabularyList.get(i).size() + " slov");
//        }
    }

}
